#ifndef VEC2_H_
#define VEC2_H_

#include "../common.h"

#include "Vec.h"

namespace physicsworks {

namespace math {

template<class T> class Vec2 : public Vec<T> {
private:
	typedef Vec<T> Base;

public:
	T &x, &y;
	
	using Vec<T>::operator*;
	using Vec<T>::operator();
	using Vec<T>::operator-;

	Vec2<T>() : Vec<T>(2), x(Base::arr[0]), y(Base::arr[1]) {}
	Vec2<T>(const Vec<T>& v) : Vec<T>(v), x(Base::arr[0]), y(Base::arr[1]) {
		// The provided vector must be a two dimensional one
	}
	Vec2<T>(const Vec2<T>& v) : Vec<T>(v), x(Base::arr[0]), y(Base::arr[1]) {}
	Vec2<T>(T X, T Y, T Z) : Vec<T>(2), x(Base::arr[0]), y(Base::arr[1]) {
		x = X; y = Y;
	}
	Vec2<T>(const T v[2]) : Vec<T>(2), x(Base::arr[0]), y(Base::arr[1]) {
		x = v[0]; y = v[1];
	}

	/**
	 * Returns the vector's length.
	 */
	T length() const {
		return sqrt((*this) * (*this));
	}

	/**
	 * Normalizes the vector.
	 * 
	 * To deal with very small vectors, it first scales the vector by 1/abs(max(x,y))
	 * then normalizes it.
	 */
	Vec2<T>& normalize() {
		std::valarray<T> arra = std::abs(Base::arr);
		*this /= arra.max();
		T l = length();
	 	
		Assert<EUndefMathOpt>(!DMATH || !equal(l, T(0)), "The vector's length must be nonzero to normalize it");
	 	
		return *this = (*this) / l;
	}
	
	/**
	 * Returns the dot product.
	 */
	const T operator * (const Vec2<T>& v) const {
		T r = 0;
		for (size_t i = 0; i < 2; i++) {
			r += this->arr[i] * v.arr[i];
		}
		return r;
	}
	
	const Vec2<T> operator - (const Vec2<T>& v) const {
		Vec2<T> r = *this;
		return r -= v;
	}
	
	/**
	 * Assigns the other vector.
	 */
	Vec2<T>& operator = (const Vec2<T>& v) {
		Base::operator=(v);
		return *this;
	}
	
	void operator () (const Vec<T>& v) {
		x = v(0);
		y = v(1);
	}
	
	void operator () (T X, T Y) {
		x = X; y = Y;
	}
	 
	Vec2<T>& rotate90CounterCC() {
		T X = x;
		x = -y;
		y = x;
	
		return this;
	}

};

}

}

#endif /*VEC2_H_*/
